package com.boot.modules.auth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.boot.common.constant.GlobalVar;
import com.boot.common.constant.MessageConstant;
import com.boot.common.constant.RedisConstant;
import com.boot.common.constant.SystemConstant;
import com.boot.common.result.Result;
import com.boot.modules.auth.service.AuthService;
import com.boot.modules.profile.service.ProfileService;
import com.boot.system.entity.SysUser;
import com.boot.system.service.UserService;
import com.boot.util.JwtUtil;
import com.boot.util.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Map;

@Slf4j
@RequiredArgsConstructor
@Service("authService")
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;

    private final ProfileService profileService;

    private final UserService userService;

    private final RedisUtil redisUtil;

    private final JwtUtil jwtUtil;

    private final PasswordEncoder passwordEncoder;

    @Override
    public Result<String> login(Map<String, Object> dataParam, String channel, String ip) {
        //如果有验证码，需要先验证
        String captchaKey = null;
        if (dataParam.get("captcha") != null && dataParam.get("uuid") != null) {
            captchaKey = StrUtil.format(RedisConstant.User.CAPTCHA, dataParam.get("uuid"));
            Object captchaCode = redisUtil.get(captchaKey);
            if (captchaCode == null){
                return Result.error(MessageConstant.CAPTCHA_EXPIRED);
            }
            if (!dataParam.get("captcha").toString().equalsIgnoreCase(captchaCode.toString())) {
                return Result.error(MessageConstant.CAPTCHA_ERROR);
            }
        }
        String username = (String) dataParam.get("username");
        String password = (String) dataParam.get("password");
        //记录登录错误次数
        String loginErrorKey = StrUtil.format(RedisConstant.Auth.LOGIN_ERROR, username);
        //查询用户信息
        SysUser sysUser = profileService.findByUsername(username);
        if (sysUser != null){
            // 验证密码
            if (!passwordEncoder.matches(password, sysUser.getPassword())) {
                // 记录错误次数
                Long count = redisUtil.increment(loginErrorKey, 1);
                if (count >= SystemConstant.LOGIN_ERROR_COUNT){
                    //删除错误次数
                    redisUtil.delete(loginErrorKey);
                    //修改用户状态
                    userService.updateUserStatus(username, null, null, 0);
                    return Result.error(MessageConstant.USER_LOCKED);
                }
            }
            // 登录成功，判断用户是否被禁用
            if (sysUser.getIsDeleted() == 1 && !"super".equals(sysUser.getUsername())){
                return Result.error(MessageConstant.USERNAME_NOT_EXIST);
            }
            if (sysUser.getStatus() == 0){
                return Result.error(MessageConstant.USER_LOCKED);
            }
        }else{
            return Result.error(MessageConstant.USERNAME_NOT_EXIST);
        }
        // 认证用户
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成JWT令牌
        String token = jwtUtil.generateToken(username, channel);
        // 将令牌存储到Redis
        String tokenKey = StrUtil.format(RedisConstant.Auth.TOKEN, channel, username);
        //按平台存储令牌时间
        if (SystemConstant.Channel.PC.equals(channel)) {
            redisUtil.set(tokenKey, token, SystemConstant.PC_TOKEN_EXPIRE);
        } else if (SystemConstant.Channel.APP.equals(channel)) {
            redisUtil.set(tokenKey, token, SystemConstant.APP_TOKEN_EXPIRE);
        } else {
            return Result.error(MessageConstant.CHANNEL_ERROR);
        }
        // 删除登录错误次数
        if (loginErrorKey != null){
            redisUtil.delete(loginErrorKey);
        }
        //验证码正确，删除验证码
        if (captchaKey != null){
            redisUtil.delete(captchaKey);
        }
        // 记录登录时间和登录IP
        userService.updateLoginIp(username, null, null, ip);
        return Result.success(token);
    }

    @Override
    public Result<?> register(Map<String, Object> dataParam) {
        // 创建新用户
        SysUser user = new SysUser();
        //账号（判断是否存在）
        if (dataParam.get("username") != null) {
            user.setUsername((String) dataParam.get("username"));
            if (profileService.findByUsername((String) dataParam.get("username")) != null) {
                return Result.error(MessageConstant.USERNAME_EXIST);
            }
        }
        //密码
        user.setPassword(passwordEncoder.encode((String) dataParam.get("password")));
        //邮箱（判断是否存在）
        if (dataParam.get("email") != null) {
            user.setEmail((String) dataParam.get("email"));
            if (profileService.findByEmail((String) dataParam.get("email")) != null) {
                return Result.error(MessageConstant.EMAIL_EXIST);
            }
        }
        //手机号（判断是否存在）
        if (dataParam.get("phone") != null) {
            user.setPhone((String) dataParam.get("phone"));
            if (profileService.findByPhone((String) dataParam.get("phone")) != null) {
                return Result.error(MessageConstant.PHONE_EXIST);
            }
        }
        // 部门
        user.setDeptId(3L);
        user.setDeptTreePath("0,1,2,");
        //启用状态
        user.setStatus(1);
        //默认角色
        user.setRoles("user");
        //时间戳
        user.setCreateTime(GlobalVar.systemTime);
        // 保存用户
        boolean result = profileService.register(user);
        if (result) {
            return Result.success("注册成功", null);
        } else {
            return Result.error("注册失败");
        }
    }

    @Override
    public Result<?> logout(String channel) {
        // 获取当前认证用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            String username = authentication.getName();
            // 从Redis中删除令牌
            String tokenKey = StrUtil.format(RedisConstant.Auth.TOKEN, channel, username);
            if (redisUtil.hasKey(tokenKey)) {
                redisUtil.delete(tokenKey);
            }
        }
        return Result.success();
    }

}
